/*
 * 文件名：ResettableStreamHttpServletRequest.java
 * 版权：MoonBox 
 * 修改人：Peter
 * 修改时间：2018年9月30日
 * 修改内容：新增
 */
package com.renzhebiao.lkang.request;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.springframework.http.MediaType;

import com.google.common.net.HttpHeaders;
import com.renzhebiao.lkang.utils.EmptyTools;

/**
 * TODO 添加类的一句话简单描述。
 * <p>
 * TODO 详细描述
 * 
 * @author Peter
 * @since 1.0.0
 */
public class ResettableStreamHttpServletRequest extends HttpServletRequestWrapper {

    private byte[]                       rawData;

    private String                       uri;

    private HttpServletRequest           request;

    private ResettableServletInputStream servletStream;

    private Map<String, String[]>        params;

    private Map<String, String>          overridedHeaders;

    /**
     * 构造函数。
     * 
     * @param request HttpServletRequest
     */
    public ResettableStreamHttpServletRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
        this.servletStream = new ResettableServletInputStream();
        this.overridedHeaders = new HashMap<>();
    }

    /**
     * 覆盖ContentType
     * 
     * @param contentType 请求内容类型, {@link MediaType}
     */
    @SuppressWarnings("rawtypes")
    public void overrideContentType(String contentType) {
        Enumeration enumeration = super.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String name = (String) enumeration.nextElement();
            overridedHeaders.put(name, request.getHeader(name));
        }
        overridedHeaders.put(HttpHeaders.CONTENT_TYPE.toLowerCase(), contentType);
    }

    @Override
    public String getContentType() {
        String contentType = overridedHeaders.get(HttpHeaders.CONTENT_TYPE.toLowerCase());
        if (contentType != null) {
            return contentType;
        }
        return super.getContentType();
    }

    @Override
    public String getParameter(String name) {
        String result = "";

        Object v = params.get(name);
        if (v == null) {
            result = null;
        } else if (v instanceof String[]) {
            String[] strArr = (String[]) v;
            if (strArr.length > 0) {
                result = strArr[0];
            } else {
                result = null;
            }
        } else if (v instanceof String) {
            result = (String) v;
        } else {
            result = v.toString();
        }

        return result;
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        return params;
    }

    /**
     * setParameterMap
     * 
     * @param newParams Map
     */
    public void setParameterMap(Map<String, String[]> newParams) {
        this.params = newParams;
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public Enumeration getParameterNames() {
        return new Vector(params.keySet()).elements();
    }

    @Override
    public String getHeader(String name) {
        String headerValue = overridedHeaders.get(name);
        if (headerValue != null && !headerValue.isEmpty()) {
            return headerValue;
        }
        return super.getHeader(name);
    }

    @Override
    public Enumeration<String> getHeaders(String name) {
        // if (null != name && name.equals(StringConstants.CONTENT_TYPE)) {
        // return new Enumeration<String>() {
        //
        // private boolean hasGetted = false;
        //
        // @Override
        // public String nextElement() {
        // if (hasGetted) {
        // throw new NoSuchElementException();
        // } else {
        // hasGetted = true;
        // String contentType = overridedHeaders.get(StringConstants.CONTENT_TYPE);
        // if (contentType != null) {
        // return contentType;
        // }
        // return getHeader("content-type");
        // }
        // }
        //
        // @Override
        // public boolean hasMoreElements() {
        // return !hasGetted;
        // }
        // };
        // }
        return super.getHeaders(name);
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] result = null;

        Object v = params.get(name);
        if (v == null) {
            result = null;
        } else if (v instanceof String[]) {
            result = (String[]) v;
        } else if (v instanceof String) {
            result = new String[] {(String) v};
        } else {
            result = new String[] {v.toString()};
        }

        return result;
    }

    /**
     * 重置请求body内容
     */
    public void resetInputStream() {
        servletStream.stream = new ByteArrayInputStream(rawData);
    }

    /**
     * 重置请求body内容
     * 
     * @param newData body内容
     */
    public void resetInputStream(byte[] newData) {
        servletStream.stream = new ByteArrayInputStream(newData);
    }

    @Override
    public Enumeration<String> getHeaderNames() {
        return super.getHeaderNames();
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (rawData == null) {
            // rawData = IOS.toByteArray(this.request.getReader(), Charset.defaultCharset());
            rawData = this.readBytes(this.request.getReader(), "UTF-8");
            servletStream.stream = new ByteArrayInputStream(rawData);
        }
        return servletStream;
    }

    @Override
    public String getRequestURI() {
        return uri;
    }

    /**
     * 设置请求URI
     * 
     * @param urix uri
     */
    public void setRequestURI(String urix) {
        this.uri = urix;
    }

    @SuppressWarnings("deprecation")
    @Override
    public BufferedReader getReader() throws IOException {
        request.setCharacterEncoding("utf-8");
        if (rawData == null) {
            rawData = this.readBytes(this.request.getReader(), "UTF-8");
            if (rawData == null) {
                return null;
            }
            servletStream.stream = new ByteArrayInputStream(rawData);
        }

        return new BufferedReader(new InputStreamReader(servletStream));
    }

    /**
     * 重置ServletInputStream
     * 
     * @author 龙汀
     */
    private class ResettableServletInputStream extends ServletInputStream {

        private InputStream stream;

        @Override
        public int read() throws IOException {
            return stream.read();
        }

        @Override
        public boolean isFinished() {

            return true;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener readListener) {

        }
    }

    /**
     * 通过BufferedReader和字符编码集转换成byte数组
     * 
     * @param br
     * @param encoding
     * @return
     * @throws IOException
     */
    private byte[] readBytes(BufferedReader br, String encoding) throws IOException {
        String str = null, retStr = "";
        while ((str = br.readLine()) != null) {
            retStr += str;
        }
        if (EmptyTools.isNotNullOrEmpty(retStr)) {
            return retStr.getBytes(Charset.forName(encoding));
        }
        return null;
    }
}
